#pragma once

/**
 * @file log_stream.h
 * @brief 提供线程安全、可配置的消息/日志流接口及相关辅助组件。
 *
 * 本文件包含以下核心类型：
 * - LineBuffer：每线程的行缓冲，用于规范化分隔符并累积待输出的 token。
 * - Formatter：统一构建日志头部（时间戳、线程 ID、源位置、前缀、深度等）。
 * - SinkManager：管理输出通道（控制台/文件/自定义回调），并保证原子写出。
 * - LogStream：对外的消息流接口，封装格式化与输出能力，支持 RAII 辅助类。
 *
 * 所有注释统一采用 Doxygen 风格，便于自动化文档生成与维护。
 */

#include <stlcompat/print.h>

#include <chrono>
#include <ctime>
#include <filesystem>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <memory>
#include <mutex>
#include <sstream>
#include <string>
#include <string_view>
#include <thread>
#include <vector>

#if defined(__has_include)
#if __has_include(<source_location>) && __cplusplus >= 202002L
#include <source_location>
#define KP_HAS_SOURCE_LOCATION 1
#else
#define KP_HAS_SOURCE_LOCATION 0
#endif
#else
#define KP_HAS_SOURCE_LOCATION 0
#endif

namespace kp::io
{

// 检测是否包含占位符：识别未转义的 "{"（非 "{{"）作为占位符起点
inline bool
has_brace_placeholders(std::string_view fmt)
{
    for (size_t i = 0; i < fmt.size(); ++i)
    {
        char c = fmt[i];
        if (c == '{')
        {
            if (i + 1 < fmt.size() && fmt[i + 1] == '{')
            {
                ++i; // 跳过转义
                continue;
            }
            return true; // 发现占位符
        }
        else if (c == '}')
        {
            if (i + 1 < fmt.size() && fmt[i + 1] == '}')
            {
                ++i; // 跳过转义
                continue;
            }
            // 孤立 '}' 视为潜在格式片段，交由 vformat 处理（保持兼容）
            return true;
        }
    }
    return false;
}

// 字符串感知：可转换为 std::string_view 的类型视为“字符串样式”
template <typename T>
struct is_string_like : std::bool_constant<std::is_convertible_v<T, std::string_view>>
{
};

/**
 * @brief LineBuffer（TLS）按行缓冲并规范化分隔符。
 *
 * 提供独立的按线程行缓冲抽象，负责在一行内按需插入统一的分隔符并累积 token；
 * 保持现有 LogStream 对外 API 不变。
 */
class LineBuffer
{
public:
    LineBuffer() = default; ///< 默认构造函数。

    /**
     * @brief 不支持拷贝（内部状态基于 thread_local，不应跨对象复制）。
     */
    LineBuffer(const LineBuffer &) = delete;             ///< 删除拷贝构造。
    LineBuffer & operator=(const LineBuffer &) = delete; ///< 删除拷贝赋值。
    LineBuffer(LineBuffer &&) = default;                 ///< 允许移动构造。
    LineBuffer & operator=(LineBuffer &&) = default;     ///< 允许移动赋值。

    /**
     * @brief 每线程独立的行缓冲。
     */
    inline std::ostringstream & stream() { return tls_stream; }

    /**
     * @brief 标记当前行是否已有 token，用于规范化分隔符（避免尾部多余分隔符）。
     */
    static thread_local bool tls_has_token; ///< TLS 行状态：是否已有 token。

    /**
     * @brief 每线程的缓冲流对象。
     */
    static thread_local std::ostringstream tls_stream; ///< TLS 行缓冲流。

    /**
     * @brief 重置当前行的状态与缓冲内容。
     *
     * 将 `tls_stream` 置空并清除 `tls_has_token` 标记。
     */
    void reset_line();

    /**
     * @brief 附加一个 token，必要时插入分隔符。
     *
     * 当行内已存在 token 时，先输出分隔符，再输出新的值；否则直接输出值并标记已有
     * token。
     *
     * @tparam T 可流化输出的类型。
     * @param value 待附加的值。
     * @param delimiter 分隔符字符串。
     */
    template <typename T>
    void append_token(const T & value, const std::string & delimiter)
    {
        if (tls_has_token)
            tls_stream << delimiter;
        tls_stream << value;
        tls_has_token = true;
    }
#if KP_HAS_SOURCE_LOCATION
    // 对 std::source_location 的重载：不输出，仅忽略该 token
    inline void append_token(const std::source_location & loc, const std::string & delimiter)
    {
        (void)loc;
        (void)delimiter;
        // 不改变 tls_has_token，以避免产生前置分隔符
    }
#endif
};

/// TLS 行缓冲流定义。
inline thread_local std::ostringstream LineBuffer::tls_stream;
/// TLS 行状态定义：是否已有 token。
inline thread_local bool LineBuffer::tls_has_token = false;

inline void
LineBuffer::reset_line()
{
    tls_stream.str("");
    tls_stream.clear();
    tls_has_token = false;
}

/**
 * @brief Formatter 负责统一构建日志头部（时间戳、线程
 * ID、源位置、前缀、深度）。
 *
 * 将头部/格式化的职责集中，提供运行时可配置的格式控制并维护每线程的前缀栈与深度。
 */
class Formatter
{
public:
    Formatter() = default; ///< 默认构造函数。

    /** @brief 显式拷贝/移动：仅复制运行时配置，不涉及 TLS 状态。 */
    Formatter(const Formatter &) = default;             ///< 拷贝构造。
    Formatter & operator=(const Formatter &) = default; ///< 拷贝赋值。
    Formatter(Formatter &&) = default;                  ///< 移动构造。
    Formatter & operator=(Formatter &&) = default;      ///< 移动赋值。

    // 配置项（与 LogStream 保持一致）
    bool log_thread_id = false;                      ///< 是否在头部显示线程 ID。
    int max_depth = std::numeric_limits<int>::max(); ///< 最大显示深度，用于层级过滤。
    std::ios_base::fmtflags flags = {};              ///< 流格式标志。
    int precision = -1;          ///< 数值精度设置（<0 表示未设置）。
    int width = -1;              ///< 字段宽度设置（<0 表示未设置）。
    std::string source_file;     ///< 源文件名。
    int source_line = -1;        ///< 源代码行号（<0 未设置）。
    std::string source_function; ///< 源函数名。
    int timezone = 8;            ///< 时区偏移（小时），用于时间戳。
    bool show_source = false;    ///< 是否在头部展示源位置信息。
    std::string prefix;          ///< 明确的消息前缀（与栈区分）。
    int level = 0;               ///< 消息级别（映射自 MessageType）。
    int min_level = -1;          ///< 最小输出级别（过滤阈值）。

    /**
     * @brief 每线程前缀栈与深度计数。
     */
    static thread_local std::vector<std::string> tls_prefix_stack; ///< TLS 前缀栈。
    static thread_local int tls_depth;                             ///< TLS 当前深度。

    /**
     * @brief 每线程时间戳缓存（按秒缓存，含时区）。
     */
    static thread_local std::time_t tls_last_tt; ///< 最近一次格式化的时间戳（秒）。
    static thread_local int tls_last_tz;         ///< 缓存的时区偏移（小时）。
    static thread_local std::string tls_last_ts; ///< 缓存的时间字符串。

    /**
     * @brief 压入一个前缀到当前线程的前缀栈。
     * @param prefix 要压入的前缀字符串。
     */
    inline void push_prefix(const std::string & prefix) { tls_prefix_stack.push_back(prefix); }

    /**
     * @brief 弹出当前线程前缀栈的顶部前缀。
     */
    inline void pop_prefix()
    {
        if (!tls_prefix_stack.empty())
            tls_prefix_stack.pop_back();
    }

    /**
     * @brief 调整当前深度计数。
     * @param delta 深度增量（可为负）。
     */
    inline void add_depth(int delta) { tls_depth += delta; }

    /**
     * @brief 获取当前深度。
     * @return 当前深度值。
     */
    inline int depth() const { return tls_depth; }

    /**
     * @brief 获取当前线程的前缀栈快照。
     * @return 前缀栈副本。
     */
    inline std::vector<std::string> prefix_stack() const { return tls_prefix_stack; }

    /**
     * @brief 级别名称映射（示意）。
     * @param lv 级别数值。
     * @return 对应的级别名称字符串。
     */
    static const char * level_name(int lv)
    {
        switch (lv)
        {
            case -2:
                return "Trace";
            case -1:
                return "Debug";
            case 0:
                return "Info";
            case 1:
                return "Warning";
            case 2:
                return "Error";
            default:
                return "Info";
        }
    }

    /**
     * @brief 格式化当前时间为 "YYYY-MM-DD HH:MM:SS"，按 `timezone` 偏移小时。
     * @return 格式化的时间字符串。
     */
    std::string format_time() const
    {
        using namespace std::chrono;
        auto now = system_clock::now();
        auto shifted = now + hours(timezone);
        std::time_t tt = system_clock::to_time_t(shifted);
        if (tls_last_tz != timezone)
        {
            tls_last_tz = timezone;
            tls_last_tt = static_cast<std::time_t>(-1);
            tls_last_ts.clear();
        }
        if (tls_last_tt == tt && !tls_last_ts.empty())
        {
            return tls_last_ts;
        }
        std::tm tm_buf;
        tm_buf = *std::gmtime(&tt);
        std::ostringstream ts;
        ts << std::put_time(&tm_buf, "%Y-%m-%d %H:%M:%S");
        tls_last_tt = tt;
        tls_last_ts = ts.str();
        return tls_last_ts;
    }

    /**
     * @brief 在支持时接入 `std::source_location`，记录当前位置。
     * @param loc 源位置对象。
     */
#if KP_HAS_SOURCE_LOCATION
    inline void set_location(const std::source_location & loc)
    {
        source_file = loc.file_name();
        source_line = static_cast<int>(loc.line());
        source_function = loc.function_name();
        show_source = true;
    }
#endif

    /**
     * @brief 设置时间戳的时区偏移（小时）。
     * @param tz 时区偏移（例如东八区为 8）。
     */
    inline void set_timezone(int tz) { timezone = tz; }

    /**
     * @brief 控制是否在头部展示源位置信息。
     * @param enable 为 `true` 时显示源位置信息。
     */
    inline void enable_source(bool enable) { show_source = enable; }

    /**
     * @brief 显式设置源位置信息。
     * @param file 源文件名。
     * @param line 源代码行号。
     * @param function 源函数名（可选）。
     */
    inline void set_source(std::string file, int line, std::string function = {})
    {
        source_file = std::move(file);
        source_line = line;
        source_function = std::move(function);
    }

    /**
     * @brief 设置是否显示线程 ID。
     * @param enable 为 `true` 时显示线程 ID。
     */
    inline void set_log_thread_id(bool enable) { log_thread_id = enable; }

    /**
     * @brief 设置统一的消息前缀。
     * @param p 前缀字符串。
     */
    inline void set_prefix(std::string p) { prefix = std::move(p); }

    /**
     * @brief 设置当前消息级别。
     * @param lv 级别数值。
     */
    inline void set_level(int lv) { level = lv; }

    /**
     * @brief 构建统一的头部字符串（示意；具体格式由后续实现决定）。
     * @return 头部字符串。
     */
    std::string make_header() const
    {
        std::ostringstream h;
        h << "[" << format_time() << "]";
        h << "[" << level_name(level) << "]";
        if (!prefix.empty())
            h << "[" << prefix << "]";
        if (log_thread_id)
            h << "[" << std::this_thread::get_id() << "]";
        if (show_source && !source_file.empty() && source_line >= 0)
        {
            h << "[" << source_file << ":" << source_line;
            if (!source_function.empty())
                h << " " << source_function;
            h << "]";
        }
        if (!tls_prefix_stack.empty())
        {
            h << "[";
            for (size_t i = 0; i < tls_prefix_stack.size(); ++i)
            {
                if (i)
                    h << "/";
                h << tls_prefix_stack[i];
            }
            h << "]";
        }
        return h.str();
    }
};

/// TLS 前缀栈定义。
inline thread_local std::vector<std::string> Formatter::tls_prefix_stack;
/// TLS 当前深度定义。
inline thread_local int Formatter::tls_depth = 0;
/// TLS 最近一次格式化的时间戳（秒）。
inline thread_local std::time_t Formatter::tls_last_tt = static_cast<std::time_t>(-1);
/// TLS 缓存的时区偏移（小时）。
inline thread_local int Formatter::tls_last_tz = 0;
/// TLS 缓存的时间字符串。
inline thread_local std::string Formatter::tls_last_ts;

/**
 * @brief SinkManager
 * 负责管理所有日志输出目标（控制台、文件、自定义回调），并保证多线程并发写出时的线程安全。
 *
 * 设计初衷：
 * 1. 统一收口：所有日志最终都通过 SinkManager::write_line() 分发，便于集中加锁、过滤、统计。
 * 2. 零拷贝写出：内部持有 std::string 引用，避免在热路径上产生额外拷贝。
 * 3. 可扩展：支持任意数量的文件 sink 与自定义回调 sink，且可在运行时动态增删。
 * 4. 轮转策略：内置按文件大小与数量轮转的能力，避免单文件无限膨胀。
 * 5. 异常隔离：文件 IO 异常不会导致整个日志系统崩溃，仅影响对应 sink。
 *
 * 线程安全要点：
 * - 所有公有接口均使用 sink_mutex 进行保护，保证多线程并发调用时的顺序一致性。
 * - FileSink 内部再持有一把独立互斥锁，降低不同文件之间的锁竞争。
 * - 回调 sink
 * 在锁外调用（先快照回调链），避免重入导致的死锁；仍建议回调不抛异常且不要重入日志系统。
 *
 * 使用范例：
 * @code
 *   SinkManager mgr;
 *   mgr.attach_file_path("run.log");          // 追加写到 run.log
 *   mgr.attach_sink([](const std::string& s){ send_to_remote(s); });
 *   mgr.write_line("[INFO] hello world\n");   // 并发安全写出
 * @endcode
 */
class SinkManager
{
public:
    /** @brief 默认构造，不产生任何输出目标，所有配置后续动态添加。 */
    SinkManager() = default;

    /** @brief 禁用拷贝，避免多实例间共享状态导致的重复释放或竞争。 */
    SinkManager(const SinkManager &) = delete;
    SinkManager & operator=(const SinkManager &) = delete;

    /** @brief 启用移动，支持工厂函数或容器存储，转移后原实例处于空状态。 */
    SinkManager(SinkManager &&) = default;
    SinkManager & operator=(SinkManager &&) = default;

    /**
     * @brief 单一自定义 sink 回调，兼容旧接口，优先级低于 sinks 列表。
     *
     * 若同时设置 sink 与 sinks，则先调用 sink，再遍历 sinks。
     * 设置为 nullptr 可禁用。
     */
    std::function<void(const std::string &)> sink;

    /**
     * @brief 复合 sink 列表，支持任意数量回调，按插入顺序依次执行。
     *
     * 设计为 std::vector 而非 std::list，利用连续内存提升缓存局部性；
     * 由于写日志为低频操作，vector 的插入/删除开销可接受。
     */
    std::vector<std::function<void(const std::string &)>> sinks;

    /**
     * @brief 保护以上两个回调容器以及文件 sink 列表的互斥锁。
     *
     * 使用 std::mutex 而非读写锁，因为写日志为写多读少场景；
     * 锁粒度较粗，但实现简单，后续若出现性能瓶颈可拆分为多把锁。
     */
    mutable std::mutex sink_mutex;

    /**
     * @brief 控制台开关。为 true 时，write_line() 默认将日志输出到 std::cout。
     *
     * 该标志受 sink_mutex 保护，可在运行时动态关闭，用于线上环境静默日志。
     */
    bool show_on_screen = true;

    /**
     * @brief FileSink 是对单个日志文件的封装，支持追加写、大小轮转、备份数量限制。
     *
     * 设计要点：
     * 1. 使用 shared_ptr<std::ofstream> 而非裸指针，便于外部获取流对象进行额外操作（如手动
     * flush）。
     * 2. 所有公有接口均加锁，保证多线程并发 write()/rotate() 的安全。
     * 3. 轮转策略采用“固定备份数 + 顺序重命名”方案，避免时间戳方案在高并发下产生重复文件名。
     * 4. 写入字节数按字符串长度累加，不依赖 std::ofstream::tellp()，避免多线程 tellp 竞争。
     * 5. 提供异常安全保证：rotate 失败时，原文件继续写入，避免日志丢失。
     */
    class FileSink
    {
    public:
        /** @brief 默认构造，不打开任何文件，后续通过 open()/rotate() 绑定路径。 */
        FileSink() = default;

        /**
         * @brief 直接使用外部传入的 ofstream 构造，适用于单元测试或特殊流（如 std::stringstream）。
         * @param fs 必须已打开且生命周期由外部保证，FileSink 仅持有引用。
         */
        explicit FileSink(std::shared_ptr<std::ofstream> fs);

        /**
         * @brief 便捷构造，立即打开指定路径的文件。
         * @param path 文件绝对或相对路径，若所在目录不存在则抛出异常。
         * @param append true 追加写，false 覆盖写。
         */
        explicit FileSink(const std::string & path, bool append = true);

        /**
         * @brief 打开或重新打开文件。
         * @param path 目标文件路径。
         * @param append 写入模式，true 为追加，false 为截断。
         * @throw std::runtime_error 当文件无法打开时抛出。
         */
        void open(const std::string & path, bool append = true);

        /** @return 当前是否已关联且成功打开文件。 */
        bool is_open() const;

        /**
         * @brief 写出一条完整日志行。
         * @param line 已包含换行符的字符串，内部不再额外追加 '\n'。
         * @note 若开启 _flush_on_write，则每次 write 后自动 flush。
         */
        void write(const std::string & line);

        /** @return 内部持有的 ofstream 共享指针，外部可用于手动 flush 或进一步写入。 */
        std::shared_ptr<std::ofstream> stream() const;

        /** @brief 关闭文件，若已关闭则无副作用。 */
        void close();

        /**
         * @brief 重新打开原路径文件，用于日志轮转后恢复写入。
         * @note 若路径为空或文件已打开，则直接返回。
         */
        void reopen();

        /**
         * @brief 主动切换到新文件，常用于按日期或大小手动轮转。
         * @param new_path 新文件路径，原文件将按策略关闭。
         * @param append 新文件的写入模式。
         */
        void rotate(const std::string & new_path, bool append = true);

        /**
         * @brief 配置自动轮转策略。
         * @param max_bytes 单文件字节上限，0 表示不限制。
         * @param max_files 轮转时保留的备份数，0 表示不备份。
         * @note 设置后，每次 write 会检测 _bytes_written，超过阈值自动触发轮转。
         */
        void configure_rotation(std::size_t max_bytes, std::size_t max_files);

        /** @brief 控制是否每次 write 后立刻 flush，平衡安全性与性能。 */
        void set_flush_on_write(bool enable);

    private:
        /**
         * @brief 在锁内执行备份重命名与创建新文件，异常安全。
         * @note 仅由 write() 在检测到 _bytes_written >= _max_bytes 时调用。
         */
        void rotate_with_backup_unlocked();

        std::shared_ptr<std::ofstream> _stream; ///< 实际文件流，空指针表示未打开。
        std::string _path;             ///< 当前关联的文件路径，用于 reopen/rotate。
        bool _append{true};            ///< 打开模式，影响 reopen 行为。
        std::size_t _bytes_written{0}; ///< 已写入字节计数，用于触发大小轮转。
        std::size_t _max_bytes{0};     ///< 单文件大小上限，0 表示禁用自动轮转。
        std::size_t _max_files{0};     ///< 备份数量上限，0 表示不保留备份。
        bool _flush_on_write{true};    ///< 是否立即刷新，默认 true 保证日志不丢。
        mutable std::mutex _mtx;       ///< 保护本对象所有数据成员。
    };

    /**
     * @brief 附加一个已构造的 FileSink，转移所有权到 SinkManager。
     * @param fs 非空指针，转移后外部不再持有。
     */
    void attach_file_sink(std::unique_ptr<FileSink> fs);

    /**
     * @brief 便捷接口，直接附加一个 ofstream，内部包装为 FileSink。
     * @param fs 必须已打开，生命周期由 SinkManager 接管。
     */
    void set_file_stream(std::shared_ptr<std::ofstream> fs);

    /**
     * @brief 获取第一个文件流的共享指针，用于兼容旧代码。
     * @return 若不存在文件 sink，返回空 shared_ptr。
     */
    std::shared_ptr<std::ofstream> get_file_stream() const;

    /** @brief 便捷接口，根据路径创建并附加 FileSink。 */
    void attach_file_path(const std::string & path, bool append = true);

    /** @return 当前是否存在任何文件 sink。 */
    bool has_file_sinks() const;

    /** @return 已附加的文件 sink 数量。 */
    size_t file_sink_count() const;

    /** @brief 关闭并清空所有文件 sink，回调 sink 不受影响。 */
    void clear_file_sinks();

    /** @brief 仅关闭文件，不释放 FileSink 对象，可用于临时暂停文件输出。 */
    void close_file_sinks();

    /**
     * @brief 对所有文件 sink 执行 rotate，常用于按日期统一轮转。
     * @param new_path 新文件路径，若为空则使用原路径覆盖写。
     * @param append 新文件写入模式。
     */
    void rotate_file_sinks(const std::string & new_path, bool append = true);

    /**
     * @brief 统一配置所有文件 sink 的轮转参数。
     * @param max_bytes 单文件大小上限。
     * @param max_files 备份数量。
     */
    void configure_file_rotation(std::size_t max_bytes, std::size_t max_files);

    /** @brief 统一设置所有文件 sink 的立即刷新标志。 */
    void set_flush_on_write(bool enable);

    /**
     * @brief 追加一个自定义回调 sink，线程安全。
     * @param fn 回调函数，签名必须为 void(const std::string&)，异常由调用者处理。
     */
    void attach_sink(std::function<void(const std::string &)> fn);

    /** @brief 清空所有回调 sink（含单 sink 与 sinks 列表），文件 sink 不受影响。 */
    void clear_sinks();

    /**
     * @brief 核心写出接口，所有日志最终通过此函数分发。
     * @param line 已格式化完成的完整日志行，通常已包含换行符。
     *
     * 执行流程：
     * 1. 若 show_on_screen 为 true，输出到 std::cout 并 flush。
     * 2. 遍历所有 FileSink，调用 write()。
     * 3. 若设置了单 sink，则调用之。
     * 4. 遍历 sinks 列表，依次调用。
     *
     * 以上步骤均在 sink_mutex 锁内完成，保证多线程顺序一致。
     */
    void write_line(const std::string & line);

private:
    std::vector<std::unique_ptr<FileSink>> _file_sinks; ///< 动态数组，支持任意数量文件 sink。
    bool _file_sink_attached{false}; ///< 冗余标志，加速 has_file_sinks() 判断。
};

/**
 * @brief 统一、线程安全、可扩展的日志/消息流接口。
 *
 * LogStream 将“格式化 + 多级过滤 + 多目标输出”三大职责封装为单一入口，
 * 对外提供“流式 <<”与“函数式 ()”两种写法，并支持：
 * 1. 运行时调整日志级别、分隔符、前缀、深度、时区等；
 * 2. 同时向控制台、文件、自定义回调写出，且保证多线程并发安全；
 * 3. 按文件大小/数量自动轮转，避免单文件无限膨胀；
 * 4. 通过 RAII 辅助类（Prefix/Depth）自动维护线程局部前缀栈与深度计数；
 * 5. 支持 master-only 模式，便于 MPI/多进程场景下仅让 rank 0 输出；
 * 6. 兼容 std::source_location（C++20），一键记录代码位置。
 *
 * 设计要点：
 * - 底层依赖三个独立模块：LineBuffer（TLS
 * 行缓冲）、Formatter（头部格式化）、SinkManager（输出目标管理），
 *   各模块可单独测试与替换，降低耦合。
 * - 所有“配置变更”均通过 std::mutex 保护，避免并发读写导致数据竞争；
 *   真正的写出路径使用 SinkManager 内部锁，保证多线程顺序一致。
 * - 采用 PIMPL 手法（unique_ptr 托管实现）隐藏内部状态，保持头文件轻量，
 *   同时支持拷贝构造/赋值——拷贝时仅复制配置，不共享 TLS 状态，确保线程间互不干扰。
 * - 模板化的 operator() 与 append() 允许用户传入任意可流化类型或容器区间，
 *   并在编译期自动识别 std::source_location，实现“零成本”代码位置记录。
 * - 全局实例（message/debug/warning/error/logger）在头文件内直接定义，
 *   依赖 C++17 inline 变量保证跨翻译库唯一性，用户可即用即写：
 *   @code
 *     kp::io::message("hello", 123, 3.14);          // 控制台 + kp.log
 *     kp::io::debug(std::source_location::current(), // 记录文件名、行号、函数
 *                   "vector size =", vec.size());
 *   @endcode
 */
class LogStream
{
public:
    /**
     * @brief 预定义日志级别，映射到 Formatter 内部 int 级别。
     *
     * 与 syslog 级别错开，预留负值给 debug，便于后续扩展 trace(-2)、critical(3) 等。
     */
    enum MessageType
    {
        trace = -2,  ///< 追踪信息，比 debug 更细粒度，便于更严格审计。
        debug = -1,  ///< 调试信息，默认被 min_level 过滤。
        normal = 0,  ///< 普通信息，默认输出。
        warning = 1, ///< 警告，默认输出。
        error = 2    ///< 错误，默认输出。
    };

    /**
     * @brief 构造时即绑定“级别 + 前缀 + 控制台开关 + 可选文件”。
     *
     * 文件路径若为空则不关联任何文件；若非空则立即尝试创建 FileSink，
     * 失败时仅记录失败，不影响控制台与其他 sink，保证健壮性。
     *
     * @param message_type  初始消息级别，影响后续默认过滤阈值。
     * @param prefix        统一前缀，附加在头部，与 TLS 前缀栈分离。
     * @param show_on_screen 是否同时输出到 std::cout，可随时开关。
     * @param file_name     可选日志文件路径，传入空字符串表示不写文件。
     */
    LogStream(MessageType message_type = normal,
              const std::string & prefix = "",
              bool show_on_screen = true,
              const std::string & file_name = "");

    /**
     * @brief 拷贝构造：仅复制配置，不共享 TLS 状态。
     *
     * 新实例拥有独立的 LineBuffer/Formatter/SinkManager，但 Formatter 的配置
     *（级别、前缀、时区等）从源对象复制，保证“配置快照”语义。
     */
    LogStream(const LogStream & other);

    /**
     * @brief 拷贝赋值：线程安全，先加锁再复制配置。
     */
    LogStream & operator=(const LogStream & other);

    /**
     * @brief 析构：由 unique_ptr 自动释放资源，无手动清理负担。
     */
    ~LogStream();

    /*--------------------------------------------------------------------
     *  master-only 模式：用于 MPI/多进程场景，仅让“主”进程输出。
     *--------------------------------------------------------------------*/
    /**
     * @brief 开启或关闭 master-only 模式。
     *
     * 开启后，后续所有写出操作会先调用 is_master() 判断，
     * 非 master 直接丢弃，避免多进程重复刷屏。
     *
     * @param only_master true 开启，false 关闭。
     */
    void switch_only_master(bool only_master);

    /**
     * @brief 设置自定义“主进程”判定回调。
     *
     * 若未设置，则默认返回 true，即所有进程都视为 master。
     * 回调异常时按 true 处理，防止因用户代码抛异常导致日志系统崩溃。
     *
     * @param fn 无参可调用对象，返回 true 表示当前进程为 master。
     */
    void set_master_checker(std::function<bool()> fn);

    /**
     * @brief 查询当前是否处于 master 身份。
     *
     * 若用户未提供回调，则恒返回 true。
     */
    bool is_master() const;

    /*--------------------------------------------------------------------
     *  基础配置接口：级别、分隔符、时区、线程 ID、深度等。
     *--------------------------------------------------------------------*/
    /**
     * @brief 设置最小输出级别，低于该级别的日志将被过滤。
     *
     * 例如 set_min_log_level(warning) 后，debug/normal 均不会输出。
     *
     * @param type 枚举级别，内部映射到 int。
     */
    void set_min_log_level(MessageType type);

    /**
     * @brief 设置 token 分隔符（字符串版本）。
     *
     * 影响 operator() 与 append() 在相邻 token 之间插入的字符串，
     * 默认单空格 " "。
     */
    void set_delimiter(std::string d);

    /**
     * @brief 设置 token 分隔符（单字符重载）。
     */
    void set_delimiter(char d);

    /**
     * @brief 获取当前分隔符副本。
     */
    std::string delimiter() const;

    /**
     * @brief 将枚举级别转换为内部 int，供 Formatter 使用。
     */
    int message_type_to_log_level(MessageType type) const;

    /*--------------------------------------------------------------------
     *  格式化与写出底层接口。
     *--------------------------------------------------------------------*/
    /**
     * @brief 根据当前 Formatter 配置，为原始内容包装完整头部。
     *
     * 例如：
     * @code
     *   build_message("hello") -> "[2025-06-19 12:00:00][Info][prefix] hello"
     * @endcode
     *
     * @param content 用户原始消息，允许为空。
     * @return 带头部的完整单行字符串（末尾无换行）。
     */
    std::string build_message(const std::string & content) const;

    /**
     * @brief 底层写出接口，先通过 should_output() 过滤，再交 SinkManager 分发。
     *
     * @param message 已格式化好的完整字符串（可含换行）。
     * @param level   消息级别，用于二次过滤。
     */
    void emit_message(const std::string & message, int level) const;

    /**
     * @brief 综合过滤条件：master-only + min_level。
     *
     * @param level 待写出级别。
     * @return true 允许写出，false 丢弃。
     */
    bool should_output(int level) const;

    /*--------------------------------------------------------------------
     *  行缓冲相关：获取流、手动触发写出。
     *--------------------------------------------------------------------*/
    /**
     * @brief 获取当前线程的底层 std::ostringstream，用于高级自定义写入。
     *
     * 注意：直接写入后需手动调用 emit_buffered()/emit_all_buffered()
     * 才能将内容真正发出；否则仅停留在缓冲区。
     */
    std::ostringstream & get_stream();

    /**
     * @brief 将当前行缓冲内容发出，**不**自动追加换行符。
     *
     * 适用于已手动写入 '\n' 或希望多行拼接的场景。
     */
    void emit_buffered();

    /**
     * @brief 将当前行缓冲内容发出，**自动**追加换行符。
     *
     * 最常用的“刷新”接口，等价于 std::endl 语义。
     */
    void emit_all_buffered();

    /*--------------------------------------------------------------------
     *  TLS 前缀栈与深度：用于层级缩进、模块路径等。
     *--------------------------------------------------------------------*/
    /**
     * @brief 向当前线程前缀栈压入一个前缀。
     *
     * 前缀栈影响 Formatter::make_header() 的输出顺序，
     * 典型用法：
     * @code
     *   {
     *     LogStream::Prefix _(stream, "ModuleA");
     *     stream("doing job");
     *   } // 出作用域自动弹栈
     * @endcode
     */
    void push_prefix_tls(const std::string & prefix);

    /**
     * @brief 弹出当前线程前缀栈顶部前缀。
     */
    void pop_prefix_tls();

    /**
     * @brief 调整当前线程深度计数，用于控制缩进或层级过滤。
     *
     * 正数表示加深，负数表示回退；与 Formatter::max_depth 配合使用。
     */
    void add_depth_tls(int delta);

    /*--------------------------------------------------------------------
     *  流式运算符：支持 std::endl / std::flush 及自定义操纵符。
     *--------------------------------------------------------------------*/
    /**
     * @brief 追加任意可流化类型到行缓冲。
     */
    template <typename T>
    LogStream & operator<<(const T & value)
    {
        get_stream() << value;
        return *this;
    }

    /**
     * @brief 重载操纵符（如 std::endl、std::flush）。
     *
     * 遇到 std::endl 时自动调用 emit_all_buffered()；
     * 遇到 std::flush 时调用 emit_buffered() 并 flush 底层流；
     * 其他操纵符直接透传给内部 ostringstream。
     */
    LogStream & operator<<(std::ostream & (*manip)(std::ostream &));

    /*--------------------------------------------------------------------
     *  输出目标管理：回调、文件、控制台。
     *--------------------------------------------------------------------*/
    /**
     * @brief 附加自定义回调 sink，可多次调用形成回调链。
     *
     * 回调在 SinkManager 锁内执行，因此应保证不抛异常、不重入日志系统。
     */
    void attach_sink(std::function<void(const std::string &)> sink);

    /**
     * @brief 是否已关联文件（含文件 sink）。
     */
    bool has_file() const;

    /**
     * @brief 获取第一个文件流的共享指针，兼容旧代码。
     *
     * 若不存在文件 sink，返回空指针。
     */
    std::shared_ptr<std::ofstream> get_file_stream() const;

    /**
     * @brief 获取控制台流引用，默认返回 std::cout。
     *
     * 用于需要直接写控制台的场景（如进度条），不受 should_output() 过滤。
     */
    std::ostream & get_console();

    /**
     * @brief 获取底层 SinkManager 引用，用于高级配置（轮转、flush 等）。
     */
    SinkManager & sinks();

    /**
     * @brief 获取底层 Formatter 引用，用于高级配置（时区、源位置等）。
     */
    Formatter & formatter();

    /*--------------------------------------------------------------------
     *  文件相关便捷封装：统一收口到 SinkManager。
     *--------------------------------------------------------------------*/
    void attach_file_sink(const std::string & path, bool append = true);
    void clear_file_sinks();
    size_t file_sink_count() const;
    bool has_file_sinks() const;
    void close_file_sinks();
    void rotate_file_sinks(const std::string & new_path, bool append = true);
    void set_output_file(const std::string & path, bool append = true);
    void configure_file_rotation(std::size_t max_bytes, std::size_t max_files);
    void set_flush_on_write(bool enable);

    /*--------------------------------------------------------------------
     *  格式控制：深度、线程 ID、时区。
     *--------------------------------------------------------------------*/
    void set_max_depth(int max_depth);
    int max_depth() const;
    void log_thread_id(bool enable);
    void set_timezone(int tz);

    /*--------------------------------------------------------------------
     *  RAII 辅助类：Prefix / Depth。
     *--------------------------------------------------------------------*/
    /**
     * @brief RAII 前缀作用域守卫。
     *
     * 构造时压栈，析构时弹栈；支持提前 release()，避免重复弹栈。
     */
    class Prefix
    {
    public:
        Prefix(LogStream & stream, const std::string & prefix);
        ~Prefix();
        void release();

    private:
        LogStream & _stream;
        bool _active{false};
    };

    /**
     * @brief RAII 深度作用域守卫。
     *
     * 构造时增加深度，析构时回退；支持提前 release()。
     */
    class Depth
    {
    public:
        Depth(LogStream & stream, int delta);
        ~Depth();
        void release();

    private:
        LogStream & _stream;
        int _delta{0};
        bool _active{false};
    };

    /*--------------------------------------------------------------------
     *  函数式写法：支持任意数量参数，自动识别 source_location。
     *--------------------------------------------------------------------*/
    /**
     * @brief 函数式调用接口，一次性输出多个 token。
     *
     * 示例：
     * @code
     *   stream("error code:", 404, "reason:", std::string("not found"));
     * @endcode
     *
     * 若编译器支持 C++20 且传入第一个参数为 std::source_location，
     * 则自动记录代码位置并启用 show_source。
     *
     * @tparam Args 可流化类型或 std::source_location。
     * @return *this，支持链式调用。
     */
    // 函数式调用重载：按首参是否“字符串样式”区分格式化/拼接路径
    template <typename T, typename... Args>
    std::enable_if_t<!is_string_like<std::decay_t<T>>::value, LogStream &>
    operator()(T && head, Args &&... tail);
    template <typename T, typename... Args>
    std::enable_if_t<is_string_like<std::decay_t<T>>::value, LogStream &>
    operator()(T && fmt, Args &&... args);

#if KP_HAS_SOURCE_LOCATION
    /**
     * @brief 显式传入 source_location 的重载，便于宏封装。
     */
    template <typename... Args>
    LogStream & operator()(const std::source_location & loc, Args &&... args);
    // 显式位置 + 函数式调用重载
    template <typename T, typename... Args>
    std::enable_if_t<is_string_like<std::decay_t<T>>::value, LogStream &>
    operator()(const std::source_location & loc, T && fmt, Args &&... args);
    template <typename T, typename... Args>
    std::enable_if_t<!is_string_like<std::decay_t<T>>::value, LogStream &>
    operator()(const std::source_location & loc, T && head, Args &&... tail);
#endif

    /*--------------------------------------------------------------------
     *  区间追加：支持任意 Range（vector、list、set、map、原始数组等）。
     *--------------------------------------------------------------------*/
    /**
     * @brief 追加一个区间所有元素，使用当前分隔符。
     *
     * @tparam Range 支持 range-based for 的类型。
     */
    template <typename Range>
    LogStream & append(const Range & values);

    /**
     * @brief 追加一个区间所有元素，使用自定义分隔符。
     */
    template <typename Range>
    LogStream & append(const Range & values, const std::string & delimiter);

private:
    /**
     * @brief 将当前行缓冲内容包装成完整消息（含头部）。
     */
    std::string build_full_message_from_linebuffer();

    /**
     * @brief 底层刷新实现，可选是否追加换行符。
     *
     * 线程安全：内部先构造完整消息，再交 SinkManager 写出，最后重置行缓冲。
     */
    void emit_buffered_impl(bool add_newline);

    /*====================================================================
     *  数据成员
     *====================================================================*/
    std::unique_ptr<LineBuffer> _line_buffer;   ///< 每线程独立行缓冲。
    std::unique_ptr<Formatter> _formatter;      ///< 配置与头部格式化。
    std::unique_ptr<SinkManager> _sink_manager; ///< 多目标输出管理。

    mutable std::mutex _config_mutex; ///< 保护配置变更（分隔符、auto_newline 等）。

    std::string _delimiter{" "};              ///< token 分隔符。
    bool _auto_newline{true};                 ///< operator() 是否自动追加换行。
    bool _only_master{false};                 ///< 是否开启 master-only 模式。
    std::function<bool()> _is_master_checker; ///< 可选主进程判定回调。
};

inline LogStream::LogStream(MessageType message_type,
                            const std::string & prefix,
                            bool show_on_screen,
                            const std::string & file_name)
    : _delimiter(" "), _auto_newline(true), _only_master(false)
{
    _line_buffer = std::make_unique<LineBuffer>();
    _formatter = std::make_unique<Formatter>();
    _sink_manager = std::make_unique<SinkManager>();

    _formatter->set_prefix(prefix);
    _formatter->set_level(message_type_to_log_level(message_type));
    _sink_manager->show_on_screen = show_on_screen;

    if (!file_name.empty())
    {
        try
        {
            _sink_manager->attach_file_path(file_name, /*append=*/true);
        }
        catch (...)
        {
            // 文件附加失败时仍可继续使用控制台输出
        }
    }
}

inline LogStream::LogStream(const LogStream & other)
    : _delimiter(other._delimiter),
      _auto_newline(other._auto_newline),
      _only_master(other._only_master)
{
    _line_buffer = std::make_unique<LineBuffer>();
    _formatter = std::make_unique<Formatter>(*other._formatter);
    _sink_manager = std::make_unique<SinkManager>();
}

inline LogStream &
LogStream::operator=(const LogStream & other)
{
    if (this != &other)
    {
        std::lock_guard<std::mutex> lock(_config_mutex);
        _delimiter = other._delimiter;
        _auto_newline = other._auto_newline;
        _only_master = other._only_master;
        *_formatter = *other._formatter;
    }
    return *this;
}

inline LogStream::~LogStream()
{
    // 资源由智能指针自动释放
}

inline void
LogStream::switch_only_master(bool only_master)
{
    _only_master = only_master;
}

inline void
LogStream::set_master_checker(std::function<bool()> fn)
{
    _is_master_checker = std::move(fn);
}

inline bool
LogStream::is_master() const
{
    if (_is_master_checker)
    {
        try
        {
            return _is_master_checker();
        }
        catch (...)
        {
            return true; // 容错：回调异常时视作主进程
        }
    }
    return true;
}

inline void
LogStream::set_min_log_level(MessageType type)
{
    _formatter->min_level = message_type_to_log_level(type);
}

inline void
LogStream::set_delimiter(std::string d)
{
    std::lock_guard<std::mutex> lock(_config_mutex);
    _delimiter = std::move(d);
}

inline void
LogStream::set_delimiter(char d)
{
    std::lock_guard<std::mutex> lock(_config_mutex);
    _delimiter = std::string(1, d);
}

inline std::string
LogStream::delimiter() const
{
    return _delimiter;
}

inline int
LogStream::message_type_to_log_level(MessageType type) const
{
    switch (type)
    {
        case trace:
            return -2;
        case debug:
            return -1;
        case normal:
            return 0;
        case warning:
            return 1;
        case error:
            return 2;
        default:
            return 0;
    }
}

inline std::string
LogStream::build_message(const std::string & content) const
{
    std::ostringstream oss;
    oss << _formatter->make_header();
    if (!content.empty())
    {
        oss << " " << content;
    }
    return oss.str();
}

inline void
LogStream::emit_message(const std::string & message, int level) const
{
    if (!should_output(level))
        return;
    _sink_manager->write_line(message);
}

inline bool
LogStream::should_output(int level) const
{
    if (_only_master && !is_master())
        return false;
    if (level < _formatter->min_level)
        return false;
    return true;
}

inline std::ostringstream &
LogStream::get_stream()
{
    return _line_buffer->stream();
}

inline void
LogStream::emit_buffered()
{
    emit_buffered_impl(/*add_newline=*/false);
}

inline void
LogStream::emit_all_buffered()
{
    emit_buffered_impl(/*add_newline=*/true);
}

inline void
LogStream::push_prefix_tls(const std::string & prefix)
{
    _formatter->push_prefix(prefix);
}

inline void
LogStream::pop_prefix_tls()
{
    _formatter->pop_prefix();
}

inline LogStream &
LogStream::operator<<(std::ostream & (*manip)(std::ostream &))
{
    if (manip == static_cast<std::ostream & (*)(std::ostream &)>(std::endl))
    {
        emit_buffered_impl(/*add_newline=*/true);
    }
    else if (manip == static_cast<std::ostream & (*)(std::ostream &)>(std::flush))
    {
        emit_buffered_impl(/*add_newline=*/false);
    }
    else
    {
        _line_buffer->stream() << manip;
    }
    return *this;
}

inline std::string
LogStream::build_full_message_from_linebuffer()
{
    std::string content = _line_buffer->stream().str();
    return build_message(content);
}

inline void
LogStream::emit_buffered_impl(bool add_newline)
{
    std::string full = build_full_message_from_linebuffer();
    if (add_newline)
        full.push_back('\n');
    emit_message(full, _formatter->level);
    _line_buffer->reset_line();
}

inline void
LogStream::attach_sink(std::function<void(const std::string &)> sink)
{
    _sink_manager->attach_sink(std::move(sink));
}

inline bool
LogStream::has_file() const
{
    return _sink_manager->has_file_sinks();
}

inline std::shared_ptr<std::ofstream>
LogStream::get_file_stream() const
{
    return _sink_manager->get_file_stream();
}

inline void
SinkManager::attach_file_sink(std::unique_ptr<FileSink> fs)
{
    std::lock_guard<std::mutex> lock(sink_mutex);
    _file_sinks.push_back(std::move(fs));
    _file_sink_attached = true;
}

inline size_t
LogStream::file_sink_count() const
{
    return _sink_manager->file_sink_count();
}

inline bool
LogStream::has_file_sinks() const
{
    return _sink_manager->has_file_sinks();
}

inline void
LogStream::rotate_file_sinks(const std::string & new_path, bool append)
{
    _sink_manager->rotate_file_sinks(new_path, append);
}

inline void
LogStream::set_output_file(const std::string & path, bool append)
{
    _sink_manager->attach_file_path(path, append);
}

inline void
LogStream::configure_file_rotation(std::size_t max_bytes, std::size_t max_files)
{
    _sink_manager->configure_file_rotation(max_bytes, max_files);
}

inline void
LogStream::set_flush_on_write(bool enable)
{
    _sink_manager->set_flush_on_write(enable);
}

inline void
LogStream::attach_file_sink(const std::string & path, bool append)
{
    _sink_manager->attach_file_path(path, append);
}

inline void
LogStream::set_timezone(int tz)
{
    _formatter->set_timezone(tz);
}

// RAII: Prefix
inline LogStream::Prefix::Prefix(LogStream & stream, const std::string & prefix)
    : _stream(stream), _active(true)
{
    _stream.push_prefix_tls(prefix);
}

inline LogStream::Prefix::~Prefix()
{
    if (_active)
        _stream.pop_prefix_tls();
}

inline void
LogStream::Prefix::release()
{
    if (_active)
    {
        _stream.pop_prefix_tls();
        _active = false;
    }
}

// RAII: Depth
inline LogStream::Depth::Depth(LogStream & stream, int delta)
    : _stream(stream), _delta(delta), _active(true)
{
    _stream.add_depth_tls(delta);
}

inline LogStream::Depth::~Depth()
{
    if (_active)
        _stream.add_depth_tls(-_delta);
}

inline void
LogStream::Depth::release()
{
    if (_active)
    {
        _stream.add_depth_tls(-_delta);
        _active = false;
    }
}

// 非字符串首参：保持“按分隔符拼接”的原语义
template <typename T, typename... Args>
std::enable_if_t<!is_string_like<std::decay_t<T>>::value, LogStream &>
LogStream::operator()(T && head, Args &&... tail)
{
    _line_buffer->reset_line();
#if KP_HAS_SOURCE_LOCATION
    auto append_or_set_loc = [&](auto && arg)
    {
        using A = std::decay_t<decltype(arg)>;
        if constexpr (std::is_same_v<A, std::source_location>)
        {
            _formatter->show_source = true;
            _formatter->set_location(arg);
        }
        else
        {
            _line_buffer->append_token(std::forward<decltype(arg)>(arg), _delimiter);
        }
    };
    append_or_set_loc(std::forward<T>(head));
    (append_or_set_loc(std::forward<Args>(tail)), ...);
#else
    _line_buffer->append_token(std::forward<T>(head), _delimiter);
    ((_line_buffer->append_token(std::forward<Args>(tail), _delimiter)), ...);
#endif
    emit_buffered_impl(_auto_newline);
    return *this;
}

// 字符串首参：若包含占位符则使用 kp::vformat，否则退化为分隔符拼接
template <typename T, typename... Args>
std::enable_if_t<is_string_like<std::decay_t<T>>::value, LogStream &>
LogStream::operator()(T && fmt, Args &&... args)
{
    _line_buffer->reset_line();
    std::string_view fmt_sv(fmt);
    const bool use_format = has_brace_placeholders(fmt_sv);
    if (use_format)
    {
        std::string formatted = ::kp::vformat(fmt_sv, std::forward<Args>(args)...);
        _line_buffer->append_token(formatted, _delimiter);
    }
    else
    {
        // 无占位符：退化为首参 + 其余按分隔符拼接
        _line_buffer->append_token(fmt_sv, _delimiter);
        ((_line_buffer->append_token(std::forward<Args>(args), _delimiter)), ...);
    }
    emit_buffered_impl(_auto_newline);
    return *this;
}

template <typename Range>
LogStream &
LogStream::append(const Range & values)
{
    for (const auto & v : values)
    {
        _line_buffer->append_token(v, _delimiter);
    }
    return *this;
}

template <typename Range>
LogStream &
LogStream::append(const Range & values, const std::string & delimiter)
{
    for (const auto & v : values)
    {
        _line_buffer->append_token(v, delimiter);
    }
    return *this;
}

template <typename Range>
LogStream &
log(LogStream & stream, const Range & values)
{
    return stream.append(values);
}

template <typename Range>
LogStream &
log(LogStream & stream, const Range & values, const std::string & delimiter)
{
    return stream.append(values, delimiter);
}

#if KP_HAS_SOURCE_LOCATION
// 显式位置 + 首参字符串：优先使用 kp::vformat（存在占位符时）
template <typename T, typename... Args>
std::enable_if_t<is_string_like<std::decay_t<T>>::value, LogStream &>
LogStream::operator()(const std::source_location & loc, T && fmt, Args &&... args)
{
    _formatter->show_source = true;
    _formatter->set_location(loc);
    _line_buffer->reset_line();
    std::string_view fmt_sv(fmt);
    const bool use_format = has_brace_placeholders(fmt_sv);
    if (use_format)
    {
        std::string formatted = ::kp::vformat(fmt_sv, std::forward<Args>(args)...);
        _line_buffer->append_token(formatted, _delimiter);
    }
    else
    {
        _line_buffer->append_token(fmt_sv, _delimiter);
        ((_line_buffer->append_token(std::forward<Args>(args), _delimiter)), ...);
    }
    emit_buffered_impl(_auto_newline);
    return *this;
}

// 显式位置 + 非字符串首参：保持按分隔符拼接
template <typename T, typename... Args>
std::enable_if_t<!is_string_like<std::decay_t<T>>::value, LogStream &>
LogStream::operator()(const std::source_location & loc, T && head, Args &&... tail)
{
    _formatter->show_source = true;
    _formatter->set_location(loc);
    _line_buffer->reset_line();
    _line_buffer->append_token(std::forward<T>(head), _delimiter);
    ((_line_buffer->append_token(std::forward<Args>(tail), _delimiter)), ...);
    emit_buffered_impl(_auto_newline);
    return *this;
}
#endif

inline std::ostream &
LogStream::get_console()
{
    return std::cout;
}
inline SinkManager &
LogStream::sinks()
{
    return *_sink_manager;
}
inline Formatter &
LogStream::formatter()
{
    return *_formatter;
}
inline void
LogStream::clear_file_sinks()
{
    _sink_manager->clear_file_sinks();
}
inline void
LogStream::close_file_sinks()
{
    _sink_manager->close_file_sinks();
}
inline void
LogStream::set_max_depth(int max_depth)
{
    _formatter->max_depth = max_depth;
}
inline int
LogStream::max_depth() const
{
    return _formatter->max_depth;
}
inline void
LogStream::log_thread_id(bool enable)
{
    _formatter->log_thread_id = enable;
}
inline void
LogStream::add_depth_tls(int delta)
{
    _formatter->add_depth(delta);
}

inline void
SinkManager::set_file_stream(std::shared_ptr<std::ofstream> fs)
{
    std::lock_guard<std::mutex> lock(sink_mutex);
    if (_file_sinks.empty())
    {
        _file_sinks.push_back(std::make_unique<FileSink>(std::move(fs)));
        _file_sink_attached = true;
    }
}

inline std::shared_ptr<std::ofstream>
SinkManager::get_file_stream() const
{
    std::lock_guard<std::mutex> lock(sink_mutex);
    if (_file_sinks.empty())
        return {};
    return _file_sinks.front()->stream();
}

inline void
SinkManager::attach_file_path(const std::string & path, bool append)
{
    std::lock_guard<std::mutex> lock(sink_mutex);
    _file_sinks.push_back(std::make_unique<FileSink>(path, append));
    _file_sink_attached = true;
}

inline bool
SinkManager::has_file_sinks() const
{
    std::lock_guard<std::mutex> lock(sink_mutex);
    return !_file_sinks.empty();
}

inline size_t
SinkManager::file_sink_count() const
{
    std::lock_guard<std::mutex> lock(sink_mutex);
    return _file_sinks.size();
}

inline void
SinkManager::clear_file_sinks()
{
    std::lock_guard<std::mutex> lock(sink_mutex);
    for (auto & fs : _file_sinks)
    {
        fs->close();
    }
    _file_sinks.clear();
    _file_sink_attached = false;
}

inline void
SinkManager::close_file_sinks()
{
    std::lock_guard<std::mutex> lock(sink_mutex);
    for (auto & fs : _file_sinks)
    {
        fs->close();
    }
}

inline void
SinkManager::rotate_file_sinks(const std::string & new_path, bool append)
{
    std::lock_guard<std::mutex> lock(sink_mutex);
    for (auto & fs : _file_sinks)
    {
        fs->rotate(new_path, append);
    }
}

inline void
SinkManager::configure_file_rotation(std::size_t max_bytes, std::size_t max_files)
{
    std::lock_guard<std::mutex> lock(sink_mutex);
    for (auto & fs : _file_sinks)
    {
        fs->configure_rotation(max_bytes, max_files);
    }
}

inline void
SinkManager::set_flush_on_write(bool enable)
{
    std::lock_guard<std::mutex> lock(sink_mutex);
    for (auto & fs : _file_sinks)
    {
        fs->set_flush_on_write(enable);
    }
}

inline void
SinkManager::attach_sink(std::function<void(const std::string &)> fn)
{
    std::lock_guard<std::mutex> lock(sink_mutex);
    sinks.push_back(std::move(fn));
}

inline void
SinkManager::clear_sinks()
{
    std::lock_guard<std::mutex> lock(sink_mutex);
    sinks.clear();
    sink = nullptr;
}

inline void
SinkManager::write_line(const std::string & line)
{
    // Snapshot callbacks under lock, invoke outside to avoid re-entrancy deadlocks
    std::function<void(const std::string &)> single_sink;
    std::vector<std::function<void(const std::string &)>> sink_list;

    {
        std::lock_guard<std::mutex> lock(sink_mutex);
        if (show_on_screen)
        {
            std::cout << line;
            std::cout.flush();
        }
        for (auto & fs : _file_sinks)
        {
            fs->write(line);
        }
        single_sink = sink;
        sink_list = sinks;
    }

    if (single_sink)
        single_sink(line);
    for (auto & fn : sink_list)
    {
        fn(line);
    }
}

// FileSink 内联实现（位于 kp 命名空间内，确保头文件自洽）
inline SinkManager::FileSink::FileSink(std::shared_ptr<std::ofstream> fs)
{
    std::lock_guard<std::mutex> lock(_mtx);
    _stream = std::move(fs);
    _bytes_written = 0;
}

inline SinkManager::FileSink::FileSink(const std::string & path, bool append)
{
    open(path, append);
}

inline void
SinkManager::FileSink::open(const std::string & path, bool append)
{
    std::lock_guard<std::mutex> lock(_mtx);
    _path = path;
    _append = append;
    _stream = std::make_shared<std::ofstream>();
    std::ios_base::openmode mode = std::ios::out | (append ? std::ios::app : std::ios::trunc);
    _stream->open(path, mode);
    if (!_stream->is_open())
    {
        _stream.reset();
        return;
    }
    try
    {
        _bytes_written = (append && std::filesystem::exists(path))
                             ? static_cast<std::size_t>(std::filesystem::file_size(path))
                             : 0u;
    }
    catch (...)
    {
        _bytes_written = 0;
    }
}

inline bool
SinkManager::FileSink::is_open() const
{
    std::lock_guard<std::mutex> lock(_mtx);
    return _stream && _stream->is_open();
}

inline void
SinkManager::FileSink::write(const std::string & line)
{
    std::lock_guard<std::mutex> lock(_mtx);
    if (!_stream || !_stream->is_open())
        return;
    (*_stream) << line;
    if (_flush_on_write)
        _stream->flush();
    _bytes_written += line.size();
    if (_max_bytes > 0 && _bytes_written >= _max_bytes)
    {
        rotate_with_backup_unlocked();
    }
}

inline std::shared_ptr<std::ofstream>
SinkManager::FileSink::stream() const
{
    std::lock_guard<std::mutex> lock(_mtx);
    return _stream;
}

inline void
SinkManager::FileSink::close()
{
    std::lock_guard<std::mutex> lock(_mtx);
    if (_stream)
    {
        if (_stream->is_open())
            _stream->close();
        _stream.reset();
    }
}

inline void
SinkManager::FileSink::reopen()
{
    open(_path, _append);
}

inline void
SinkManager::FileSink::rotate(const std::string & new_path, bool append)
{
    {
        std::lock_guard<std::mutex> lock(_mtx);
        if (_stream && _stream->is_open())
            _stream->close();
        _path = new_path;
        _append = append;
    }
    // 在释放互斥后打开文件，避免锁重入导致的死锁
    open(_path, _append);
}

inline void
SinkManager::FileSink::configure_rotation(std::size_t max_bytes, std::size_t max_files)
{
    std::lock_guard<std::mutex> lock(_mtx);
    _max_bytes = max_bytes;
    _max_files = max_files;
}

inline void
SinkManager::FileSink::set_flush_on_write(bool enable)
{
    std::lock_guard<std::mutex> lock(_mtx);
    _flush_on_write = enable;
}

inline void
SinkManager::FileSink::rotate_with_backup_unlocked()
{
    try
    {
        if (_max_files > 0)
        {
            for (std::size_t i = _max_files; i > 0; --i)
            {
                std::filesystem::path older = _path + "." + std::to_string(i);
                std::filesystem::path newer = _path + "." + std::to_string(i + 1);
                if (std::filesystem::exists(older))
                {
                    std::error_code ec;
                    std::filesystem::remove(newer, ec);
                    std::filesystem::rename(older, newer, ec);
                }
            }
            if (std::filesystem::exists(_path))
            {
                std::error_code ec;
                std::filesystem::rename(_path, _path + ".1", ec);
            }
        }
        if (_stream && _stream->is_open())
            _stream->close();
        _stream = std::make_shared<std::ofstream>();
        _stream->open(_path, std::ios::out | std::ios::trunc);
        _bytes_written = 0;
    }
    catch (...)
    {
        // 忽略轮转错误，继续写出
    }
}

/**
 * @brief 全局对象声明。
 */
inline LogStream message(LogStream::normal, "", true, "kp.log");
inline LogStream error(LogStream::error, "", true, "kp.log");
inline LogStream debug(LogStream::debug, "", true, "kp.log");
inline LogStream trace(LogStream::trace, "", true, "kp.log");
inline LogStream warning(LogStream::warning, "", true, "kp.log");
inline LogStream logger(LogStream::normal, "", false, "kp.log");

} // namespace kp::io
